package com.xxxtea.component;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.xxxtea.common.MerchantContext;
import com.xxxtea.common.UserContext;
import com.xxxtea.entity.Dish;
import com.xxxtea.entity.Order;
import com.xxxtea.entity.OrderItem;
import com.xxxtea.entity.User;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;

import java.util.HashSet;
import java.util.Set;

/**
 * MyBatis-Plus商家多租户数据隔离处理器
 * 
 * 用于实现商家级别的数据隔离，在SQL查询时自动注入merchant_id租户条件。
 * 支持指定表的隔离，自动识别@TableName注解或类名转下划线。
 * 仅商家角色生效，其他角色不隔离。
 * 
 * @author badman
 * @since 1.0.0
 */
@Slf4j
public class MerchantTenantLineHandler implements TenantLineHandler {
	/** 需要进行数据隔离的表集合 */
	private final Set<String> tableSet = new HashSet<>();

	/**
	 * 构造方法，注册需要隔离的表
	 */
	public MerchantTenantLineHandler() {
		registerField(Dish.class);
		registerField(Order.class);
//		registerField(OrderItem.class);
		log.info("启用数据隔离的表: {}, 隔离字段: [{}]", tableSet, getTenantIdColumn());
	}

	/**
	 * 注册需要隔离的表名，优先使用@TableName注解，否则用类名转下划线
	 */
	private <T> void registerField(Class<T> entityClass) {
		TableName tableName = entityClass.getAnnotation(TableName.class);
		if (tableName != null && !tableName.value().isEmpty()) {
			tableSet.add(tableName.value());
			return;
		}
		String className = entityClass.getSimpleName();
		tableSet.add(StrUtil.toUnderlineCase(className));
	}

	/**
	 * 获取租户字段名
	 * @return merchant_id
	 */
	@Override
	public String getTenantIdColumn() {
		return "merchant_id";
	}

	/**
	 * 获取当前租户ID表达式
	 * @return LongValue类型的商家ID
	 */
	@Override
	public Expression getTenantId() {
		return new LongValue(MerchantContext.getId());
	}

	/**
	 * 判断表是否需要进行数据隔离
	 * 仅商家角色且在隔离表集合中才隔离
	 * @param tableName 表名
	 * @return true=忽略隔离，false=进行隔离
	 */
	@Override
	public boolean ignoreTable(String tableName) {
		if (User.Role.MERCHANT == UserContext.getRole() && tableSet.contains(tableName)) {
			log.info("准备进行数据隔离的表: [{}], 隔离字段: [{}], 租户值: [{}]", tableName, getTenantIdColumn(), MerchantContext.getId());
			return false;
		}
		return true;
	}
}